package com.nsl.my_youlai.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nsl.my_youlai.common.exception.IllegalFrontParameters;
import com.nsl.my_youlai.common.result.UploadFileResult;
import com.nsl.my_youlai.common.utils.DateUtils;
import com.nsl.my_youlai.config.ProjectPathSetting;
import com.nsl.my_youlai.convert.DocxTemplateConverter;
import com.nsl.my_youlai.core.security.model.SysUserDetails;
import com.nsl.my_youlai.mapper.DocxTemplateMapper;
import com.nsl.my_youlai.mapper.MajorCategoryMapper;
import com.nsl.my_youlai.model.bo.DocxTemplateBo;
import com.nsl.my_youlai.model.dto.DocxTemplateDownloadInfoDto;
import com.nsl.my_youlai.model.entity.DocxTemplateEntity;
import com.nsl.my_youlai.model.entity.MajorCategoryEntity;
import com.nsl.my_youlai.model.form.TemplateDocxForm;
import com.nsl.my_youlai.model.query.DocxTemplatePageQuery;
import com.nsl.my_youlai.model.vo.docx_template.*;
import com.nsl.my_youlai.mystar.*;
import com.nsl.my_youlai.mystar.enums.NslEnumMime;
import com.nsl.my_youlai.mystar.enums.NslEnumUploadStatus;
import com.nsl.my_youlai.service.DocxTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import service.BatchFillDocxTemplateService;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class DocxTemplateServiceImpl extends ServiceImpl<DocxTemplateMapper, DocxTemplateEntity> implements DocxTemplateService {

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")

    private final  DocxTemplateConverter docxTemplateConverter;

    private final ProjectPathSetting projectPathSetting;

    private final MajorCategoryMapper majorCategoryMapper;

    @Override
    public IPage<DocxTemplateVo4Page> getDocxTemplatePage(DocxTemplatePageQuery queryParams) {
        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();

        //queryParams
        Page<DocxTemplateBo> page = new Page<>(pageNum, pageSize);
        DateUtils.toDatabaseFormat(queryParams, "startTime", "endTime");

        Page<DocxTemplateBo> docxTemplateBoPage=baseMapper.selectPageWithQueryParams(page,queryParams);


        IPage<DocxTemplateVo4Page> voPage=docxTemplateConverter.toPageVo(docxTemplateBoPage);

        return voPage;
    }

    @Override
    public DocxTemplateBo getDocxTemplateBoById(String docxTemplateUuid) {
        return baseMapper.getDocxTemplateBoById(docxTemplateUuid);
    }

    @Override
    public DocxTemplateDetailVo getDocxTemplateDetailById(String uuid) {
        DocxTemplateBo docxTemplateBo=baseMapper.getDocxTemplateBoById(uuid);
        DocxTemplateDetailVo docxTemplateDetailVo=docxTemplateConverter.toDetailVo(docxTemplateBo);
        String docxFileName= NslUtilFilePath.getFileName(docxTemplateBo.getTemplateDocxFilePath());
        String excelFileName=NslUtilFilePath.getFileName(docxTemplateBo.getTemplateExcelFilePath());
        docxTemplateDetailVo.setTemplateDocxOriginalFileName(removeUuidTag(docxFileName));
        docxTemplateDetailVo.setTemplateExcelOriginalFileName(removeUuidTag(excelFileName));

        return docxTemplateDetailVo;
    }

    @Override
    public File getTemplateFile(String uuid, NslEnumMime enumMime) {
        DocxTemplateBo docxTemplateBo=baseMapper.getDocxTemplateBoById(uuid);
        log.info("uuid = {} ",uuid);
        //Object ob=SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String filePath=projectPathSetting.getDocxTemplatePath()+"\\";
        if(enumMime.equals(NslEnumMime.OFFICE_XLSX)){
            filePath+=docxTemplateBo.getTemplateExcelFilePath();
        }else if(enumMime.equals(NslEnumMime.OFFICE_DOCX)){
            filePath+=docxTemplateBo.getTemplateDocxFilePath();
        }else{
            throw new RuntimeException("下载文件类型的参数不正确。");
        }
        log.info("filePath = {}",filePath);
        File file=new File(filePath);

        if(!file.exists()){
            throw new RuntimeException("下载文件 不存在，请联系管理员。");
        }

        return new File(filePath);
    }

    @Override
    public UploadFileResultOfDocxTemplateDataSourceExcel uploadDocxTemplateDataSourceExcel(String docxUuid, MultipartFile file) {
        //todo: 上传目录校验
        String originalFilename = file.getOriginalFilename();
        DocxTemplateBo docxTemplateBo=baseMapper.getDocxTemplateBoById(docxUuid);
        SysUserDetails sysUserDetails = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String userName=sysUserDetails.getUsername();
        log.info("getAuthentication() = {} ",sysUserDetails);


        String uploadFileUuid= NslUtilUuid.generateUuidWithOutHyphen();

        String filePath=buildUploadTemplateInfoExcelFilePath(uploadFileUuid,userName,docxTemplateBo,originalFilename);
        File saveFile=new File(filePath);

        File saveFileDir=new File(filePath.substring(0,filePath.lastIndexOf(File.separator)));
        if(!saveFileDir.exists()){
            saveFileDir.mkdirs();
        }

        UploadFileResultOfDocxTemplateDataSourceExcel uploadFileResultOfDocxTemplateDataSourceExcel=new UploadFileResultOfDocxTemplateDataSourceExcel();
        uploadFileResultOfDocxTemplateDataSourceExcel.setOriginalFileName(originalFilename);

        try {
            file.transferTo(saveFile);
            uploadFileResultOfDocxTemplateDataSourceExcel.setUploadStatusEnum(NslEnumUploadStatus.SAVE_SUCCESS);
            uploadFileResultOfDocxTemplateDataSourceExcel.setFileToken(uploadFileUuid);
            //todo: excel校验逻辑
            uploadFileResultOfDocxTemplateDataSourceExcel.setDocxTemplateDataSourceExcelVerifyInfo(null);
        } catch (IOException e) {
            uploadFileResultOfDocxTemplateDataSourceExcel.setUploadStatusEnum(NslEnumUploadStatus.SAVE_FAIL);
            uploadFileResultOfDocxTemplateDataSourceExcel.setFileToken(null);
            //todo:excel校验逻辑
            uploadFileResultOfDocxTemplateDataSourceExcel.setDocxTemplateDataSourceExcelVerifyInfo(null);
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            return uploadFileResultOfDocxTemplateDataSourceExcel;
        }

    }



    /**
     * 批量生成word文档，并下载
     * @param uploadFileUuidList 上传excel 信息表文件的,uuid
     * @param uploadFileNameList 上传excel 信息表文件的 文件名
     * @param docxUuid 模板id
     * @return 单个文件返回docx,多个文件返回压缩包
     * @throws IOException
     */
    @Override
    public DocxTemplateDownloadInfoDto buildDownloadInfoDtoOfBatchDocx(List<String> uploadFileUuidList, List<String> uploadFileNameList, String docxUuid) throws IOException {
        DocxTemplateBo docxTemplateBo=baseMapper.getDocxTemplateBoById(docxUuid);
        SysUserDetails sysUserDetails = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String userName=sysUserDetails.getUsername();

        //输入excelInfo list
        List<String> infoExcelList=new ArrayList<>();

        for (int i = 0; i < uploadFileNameList.size(); i++) {
            String uploadFileUuid=uploadFileUuidList.get(i);
            String uploadFileOriginalName=uploadFileNameList.get(i);
            String uploadFilePath=buildUploadTemplateInfoExcelFilePath(uploadFileUuid,userName,docxTemplateBo,uploadFileOriginalName);
            infoExcelList.add(uploadFilePath);
        }


        String docxTemplatePath=projectPathSetting.getDocxTemplatePath()+File.separator+docxTemplateBo.getTemplateDocxFilePath();

        log.info("docxTemplatePath = {}",docxTemplatePath);

        List<String> outputFilePathList=buildOutputDocxFilePathList(uploadFileNameList,userName,docxTemplateBo);

        //选取第一个文件的uuid作为zip文件的uuid
        String firstFilePath=outputFilePathList.get(0);
        int indexOfUnderline=firstFilePath.lastIndexOf(("_"));
        int indexOfPeriod=firstFilePath.indexOf(".");
        String uuidString=firstFilePath.substring(indexOfUnderline+1,indexOfPeriod);
        String dirPath=firstFilePath.substring(0,firstFilePath.lastIndexOf(File.separator));

        File dir=new File(dirPath);
        if(!dir.exists()){
            dir.mkdirs();
        }

        log.info("outputFilePathList = {}",outputFilePathList);
        try {
            BatchFillDocxTemplateService.batchRun(docxTemplatePath,infoExcelList,outputFilePathList);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("生成docx文件错误");
        }

        DocxTemplateDownloadInfoDto docxTemplateDownloadInfoDto=new DocxTemplateDownloadInfoDto();
        String downloadFileName=null;
        NslEnumMime downloadFileMime=null;

        //多个文件，返回压缩包，单个文件，直接返回
        File resultFile=null;
        if(outputFilePathList.size()>1){
            String zipFilePath=dirPath+File.separator+docxTemplateBo.getTemplateDocxName()+"_"+uuidString+".zip";
            resultFile=NslUtilZipUtil.zip(outputFilePathList,zipFilePath, new NslUtilZipUtil.EntryNameConverter() {
                @Override
                public String convertSourceName2EntryName(String sourceName) {
                    String extension= NslUtilFilePath.getFileExtension(sourceName);
                    int lastIndexOfUnderline=sourceName.lastIndexOf("_");
                    String tempString=sourceName.substring(0,lastIndexOfUnderline);
                    lastIndexOfUnderline=tempString.lastIndexOf("_");

                    return sourceName.substring(0,lastIndexOfUnderline)+"."+extension;
                }
            });;
            downloadFileName=docxTemplateBo.getTemplateDocxName()+"_"+NslUtilFilePath.getFileNameWithoutExtension(uploadFileNameList.get(0))+"等"+outputFilePathList.size()+"个.zip";
            log.info("downloadFileName = {}",downloadFileName);
            log.info("NslUtilFilePath.getFileNameWithoutExtension(uploadFileNameList.get(0) = {}",NslUtilFilePath.getFileNameWithoutExtension(uploadFileNameList.get(0)));
            downloadFileMime=NslEnumMime.ZIP_ZIP;

        }else{
            resultFile=new File(outputFilePathList.get(0));
            downloadFileName=docxTemplateBo.getTemplateDocxName()+"_"+NslUtilFilePath.getFileNameWithoutExtension(uploadFileNameList.get(0))+".docx";
            downloadFileMime=NslEnumMime.OFFICE_DOCX;
        }

        docxTemplateDownloadInfoDto.setDownloadFile(resultFile);


        return new DocxTemplateDownloadInfoDto(downloadFileName,resultFile,downloadFileMime);
    }

    /**
     * 上传模板文件中的docx 或 xlsx ，放置在临时目录
     * @param file
     * @return
     */
    @Override
    public UploadFileResultOfDocxTemplate uploadDocxTemplate(MultipartFile file)  {
        String tempDirBasePath= projectPathSetting.getDocxTemplateTempUploadPath();

        UploadFileResultOfDocxTemplate uploadFileResultOfDocxTemplate=new UploadFileResultOfDocxTemplate();
        uploadFileResultOfDocxTemplate.setOriginalFileName(file.getOriginalFilename());
        uploadFileResultOfDocxTemplate.setUploadStatusEnum(NslEnumUploadStatus.WAIT_TO_SAVE);

        String originalFileName=file.getOriginalFilename();
        String fileExtension=NslUtilFilePath.getFileExtension(originalFileName);
        if(!fileExtension.equalsIgnoreCase(NslEnumMime.OFFICE_DOCX.getExtension()) && !fileExtension.equalsIgnoreCase(NslEnumMime.OFFICE_XLSX.getExtension())){
            uploadFileResultOfDocxTemplate.setUploadStatusEnum(NslEnumUploadStatus.SAVE_FAIL);
            uploadFileResultOfDocxTemplate.setErrorMsg("上传文件名需以.xlsx和.docx结尾");
            return  uploadFileResultOfDocxTemplate;
        }


        String uuid=NslUtilUuid.generateUuidWithOutHyphen();
        String tempFilePath=buildLocalTempFilePath(tempDirBasePath,originalFileName,uuid);

        File saveFile=new File(tempFilePath);
        if(NslUtilFilePath.getFileExtension(tempFilePath).equalsIgnoreCase("docx")){
            uploadFileResultOfDocxTemplate.setFileType("docx");
        }
        if(NslUtilFilePath.getFileExtension(tempFilePath).equalsIgnoreCase("xlsx")){
            uploadFileResultOfDocxTemplate.setFileType("xlsx");
        }
        try {
            file.transferTo(saveFile);

            uploadFileResultOfDocxTemplate.setUploadStatusEnum(NslEnumUploadStatus.SAVE_SUCCESS);
            uploadFileResultOfDocxTemplate.setFileToken(uuid);
            return uploadFileResultOfDocxTemplate;
        } catch (IOException e) {
            log.info("写入日志");
            uploadFileResultOfDocxTemplate.setUploadStatusEnum(NslEnumUploadStatus.SAVE_FAIL);

            throw new RuntimeException(e);
        }finally {
            return uploadFileResultOfDocxTemplate;
        }

    }

    @Override
    public void addDocxTemplate(TemplateDocxForm templateDocxForm)  {
        //todo: 用户名根据 security 获取
        String username="用户名";

        MajorCategoryEntity majorCategoryLevel1=majorCategoryMapper.selectById(templateDocxForm.getMajorCategoryFirstLevelId());
        MajorCategoryEntity majorCategoryLevel2=majorCategoryMapper.selectById(templateDocxForm.getMajorCategorySecondLevelId());

        if(majorCategoryLevel1 ==null || majorCategoryLevel2 ==null || !NslUtilString.notNullAndTrimBlank(templateDocxForm.getUploadTemplateDocxFileUuid()) || !NslUtilString.notNullAndTrimBlank(templateDocxForm.getUploadTemplateExcelFileUuid())){
            throw new IllegalFrontParameters();
        }

        String majorCategoryLevel1Label=majorCategoryLevel1.getLabel();
        String majorCategoryLevel2Label=majorCategoryLevel2.getLabel();

        String tempUploadBasePath=projectPathSetting.getDocxTemplateTempUploadPath();
        String templateBasePath=projectPathSetting.getDocxTemplatePath();
        List<String> originalFilNameList=new ArrayList<>();
        originalFilNameList.add(templateDocxForm.getTemplateDocxOriginalFileName());
        originalFilNameList.add(templateDocxForm.getTemplateExcelOriginalFileName());

        String docxUuid=templateDocxForm.getUploadTemplateDocxFileUuid();
        String excelUuid=templateDocxForm.getUploadTemplateExcelFileUuid();

        String docxOriginalFileName=templateDocxForm.getTemplateDocxOriginalFileName();
        String excelOriginalFileName=templateDocxForm.getTemplateExcelOriginalFileName();

        String docxTempPath=buildLocalTempFilePath(tempUploadBasePath,docxOriginalFileName,docxUuid);
        File docxTempFile=new File(docxTempPath);
        String excelTempPath=buildLocalTempFilePath(tempUploadBasePath,excelOriginalFileName,excelUuid);
        File excelTempFile=new File(excelTempPath);

        String docxDestinationUuid=NslUtilUuid.generateUuidWithOutHyphen();
        String excelDestinationUuid=NslUtilUuid.generateUuidWithOutHyphen();

        String docxDestinationPath=buildLocalTemplateFilePath(templateBasePath,docxOriginalFileName,docxDestinationUuid,username,majorCategoryLevel1Label,majorCategoryLevel2Label);
        File docxDestinationFile=new File(docxDestinationPath);
        String excelDestinationPath=buildLocalTemplateFilePath(templateBasePath,excelOriginalFileName,excelDestinationUuid,username,majorCategoryLevel1Label,majorCategoryLevel2Label);
        File excelDestinationFile=new File(excelDestinationPath);

        try {
            Files.copy(docxTempFile.toPath(),docxDestinationFile.toPath());
            Files.copy(excelTempFile.toPath(),excelDestinationFile.toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String docxSavePath=docxDestinationPath.substring(templateBasePath.length());
        String excelSavePath=excelDestinationPath.substring((templateBasePath.length()));

        DocxTemplateEntity docxTemplateEntity=docxTemplateConverter.toEntity(templateDocxForm);
        docxTemplateEntity.setTemplateDocxFilePath(docxSavePath);
        docxTemplateEntity.setTemplateExcelFilePath(excelSavePath);
        docxTemplateEntity.setAuthorName(username);
        docxTemplateEntity.setUuid(NslUtilUuid.generateUuidWithOutHyphen());

        //todo:
        docxTemplateEntity.setRegionId(16);

        log.info("docxTemplate = {}", NslUtilJson.convert2JsonPrettyAndNull(docxTemplateEntity));
        baseMapper.insert(docxTemplateEntity);

    }

    @Override
    public TemplateDocxForm getTemplateDocxForm(String docxUuid) {
        DocxTemplateBo bo=baseMapper.getDocxTemplateBoById(docxUuid);
        if(bo==null){
            throw new IllegalFrontParameters();
        }
        TemplateDocxForm docxForm=docxTemplateConverter.toForm(bo);
        String templateDocxFilePath=bo.getTemplateDocxFilePath();
        String templateExcelFilePath=bo.getTemplateExcelFilePath();
        String docxFileName=NslUtilFilePath.getFileName(templateDocxFilePath);
        String excelFileName=NslUtilFilePath.getFileName(templateExcelFilePath);

        docxFileName=removeUuidTag(docxFileName);
        excelFileName=removeUuidTag(excelFileName);

        docxForm.setTemplateDocxOriginalFileName(docxFileName);
        docxForm.setTemplateExcelOriginalFileName(excelFileName);

        return docxForm;
    }

    @Override
    public File getTempFile(String originalFileName, String uuid) {
        String filePath=buildLocalTempFilePath(projectPathSetting.getDocxTemplateTempUploadPath(),originalFileName,uuid);
        File tmpFile=new File(filePath);

        return tmpFile;
    }

    /**
     * 将形如 abc_uuid123.docx,去掉_uuid123，变成abc.docx
     * @param strWithUuid
     * @return
     */
    @Override
    public String removeUuidTag(String strWithUuid){
        int index1=strWithUuid.lastIndexOf("_uuid");
        int index2=strWithUuid.lastIndexOf(").");
        if(index1 == -1 | index2 == -1){
            throw new RuntimeException("docxTemplate 或者  docxExcelTemplate 无uuid后缀");
        }
        return strWithUuid.substring(0,index1)+strWithUuid.substring(index2+1);
    }

    /**
     * 下载模板列表： 全量和筛选
     * @param queryParams
     * @return
     */
    @Override
    public List<DocxTemplateExportVo> listExportVo(DocxTemplatePageQuery queryParams) {
        List<DocxTemplateBo> boList=baseMapper.selectWithQueryParams(queryParams);
        List<DocxTemplateExportVo> exportVoList=docxTemplateConverter.toExportVoList(boList);

        return exportVoList;
    }


    public String buildUploadTemplateInfoExcelFilePath(String uploadFileUuid, String userName, DocxTemplateBo docxTemplateBo, String originalFilename){
        //构建上传目录字符串
        String[] uploadFilePathStrings={projectPathSetting.getDocxTemplateExcelInfoUploadPath(),userName,docxTemplateBo.getMajorCategoryFirstLevelLabel(),docxTemplateBo.getMajorCategorySecondLevelLabel()};

        String uploadFilePath=String.join(File.separator,uploadFilePathStrings);

        //构建上传文件名称字符串
        String[] fileNewNameStrings={docxTemplateBo.getTemplateSn(),docxTemplateBo.getTemplateDocxName(),uploadFileUuid, originalFilename};

        String fileNewName=String.join("_",fileNewNameStrings);

        return uploadFilePath+File.separator+fileNewName;
    }



    public List<String> buildOutputDocxFilePathList(List<String> uploadFileNameList, String username, DocxTemplateBo docxTemplateBo){
        List<String> outputDocxFilePathList= new ArrayList<>();
        for (String s : uploadFileNameList) {
            String downloadFileNameWithoutExtension=NslUtilFilePath.getFileNameWithoutExtension(s);
            String[] strings={downloadFileNameWithoutExtension,username,NslUtilUuid.generateUuidWithOutHyphen()};

            String downloadFileName=String.join("_",strings)+".docx";
            String[] fileDirPathArray={projectPathSetting.getDocxOutputBatchCreatedDocxFilePath(),docxTemplateBo.getMajorCategoryFirstLevelLabel(),docxTemplateBo.getMajorCategorySecondLevelLabel(),docxTemplateBo.getTemplateSn()+"_"+docxTemplateBo.getTemplateDocxName()};

            String fileDirPath= String.join(File.separator,fileDirPathArray);

            String filePath=fileDirPath+File.separator+downloadFileName;

            outputDocxFilePathList.add(filePath);
        }
        return outputDocxFilePathList;
    }



/**
 * 根据基准路径，将临时文件 根据用户名、专业1,2级类型，存入 模板文件目录
 * 约定： 文件名称为： abc_x1_y2_uuid(12344).docx，即文件中_uuid(12345) 为uuid部分
 * 目前路径算法定义为： 无线\宏站\用户名\设计模板(Demo)_uuid(123).docx
 * @param basePath 模板文件根路径
 * @param originalFilePath 临时文件路径list
 * @param localUuid 存入文件的uuid
 * @param userName 用户名，要求唯一
 * @return localFilePath
 **/
    private String buildLocalTemplateFilePath(String basePath,String originalFilePath,String localUuid,String userName,String majorCategoryLevel1Label,String majorCategoryLevel2Label){
        String fileNameWithoutExtension=NslUtilFilePath.getFileNameWithoutExtension(originalFilePath);
        String dirPath=basePath+File.separator+majorCategoryLevel1Label+File.separator+majorCategoryLevel2Label+File.separator+userName;
        File dir=new File(dirPath);
        if(!dir.exists()){
            dir.mkdirs();
        }

        String extension=NslUtilFilePath.getFileExtension(originalFilePath);
        String localFilePath=dirPath+File.separator+fileNameWithoutExtension+"_uuid("+localUuid+")."+extension;
        return localFilePath;
    }

    /**
     * 根据基准路径，将临时文件 根据用户名、专业1,2级类型，存入 模板文件目录
     * @param originalFileName
     * @param uuid
     * @return
     */
    private String buildLocalTempFilePath(String basePath,String originalFileName,String uuid){
        String fileNameWithoutExtension=NslUtilFilePath.getFileNameWithoutExtension(originalFileName);
        String extension=NslUtilFilePath.getFileExtension(originalFileName);
        String tempFilePath=basePath+File.separator+fileNameWithoutExtension+"_"+"uuid("+uuid+")."+extension;
        return tempFilePath;
    }


}
